From 4d883861b13448869234d3b76fe8ea8a0daba1a2 Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Fri, 24 Jun 2022 14:28:18 -0700 Subject: [PATCH] menutrackeritem: protect against use-after-free With recent updates to GLib, I now see cases where we can hit a state that has finalized before notify (which will bump the ref count back up). This is evident in GNOME Text Editor when showing a language submenu from a popover, and then dismissing the popover and subsequently the tab. With the previous commit, we at least get a warning like this, which helped track down the issue. Gtk-CRITICAL **: gtk_action_observable_unregister_observer: assertion 'GTK_IS_ACTION_OBSERVABLE (observable)' failed GLib-GObject-CRITICAL **: g_object_ref: assertion '!object_already_finalized' failed This patch fixes both of those criticals. Fixes #5009 --- gtk/gtkmenutrackeritem.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/gtk/gtkmenutrackeritem.c b/gtk/gtkmenutrackeritem.c index 11db1f4abb..8b459c7a41 100644 --- a/gtk/gtkmenutrackeritem.c +++ b/gtk/gtkmenutrackeritem.c @@ -870,16 +870,25 @@ gtk_menu_tracker_opener_finalize (GObject *object) { GtkMenuTrackerOpener *opener = (GtkMenuTrackerOpener *)object; - gtk_action_observable_unregister_observer (opener->item->observable, - opener->submenu_action, - (GtkActionObserver *)opener); + if (opener->item != NULL) + { + GtkMenuTrackerItem *item = g_object_ref (opener->item); + + g_clear_weak_pointer (&opener->item); + + gtk_action_observable_unregister_observer (item->observable, + opener->submenu_action, + (GtkActionObserver *)opener); - if (GTK_IS_ACTION_MUXER (opener->item->observable)) - gtk_action_muxer_change_action_state (GTK_ACTION_MUXER (opener->item->observable), - opener->submenu_action, - g_variant_new_boolean (FALSE)); + if (GTK_IS_ACTION_MUXER (item->observable)) + gtk_action_muxer_change_action_state (GTK_ACTION_MUXER (item->observable), + opener->submenu_action, + g_variant_new_boolean (FALSE)); - gtk_menu_tracker_item_set_submenu_shown (opener->item, FALSE); + gtk_menu_tracker_item_set_submenu_shown (item, FALSE); + + g_object_unref (item); + } g_clear_pointer (&opener->submenu_action, g_free); @@ -992,7 +1001,8 @@ gtk_menu_tracker_opener_new (GtkMenuTrackerItem *item, opener = g_object_new (gtk_menu_tracker_opener_get_type (), NULL); opener->first_time = TRUE; - opener->item = item; + + g_set_weak_pointer (&opener->item, item); if (item->action_namespace) opener->submenu_action = g_strjoin (".", item->action_namespace, submenu_action, NULL); -- 2.30.2